package com.junmeng.ayuv

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.os.Bundle
import android.util.Log
import android.util.Size
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import com.google.common.util.concurrent.ListenableFuture
import com.junmeng.ayuv.databinding.ActivityMainBinding
import com.junmeng.libyuv.jni.ConvertUtil
import com.junmeng.libyuv.jni.RotationUtil
import com.junmeng.libyuv.utils.YUVUtil
import java.io.*
import java.util.*
import java.util.concurrent.Executors


class MainActivity : BaseActivity() {
    private lateinit var mBinding: ActivityMainBinding
    private var mCameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
    private var mCamera: Camera? = null
    private var hasRowWrite = true //yuv数据是否已写入本地文件的标识
    private var hasRowRotateWrite = true //yuv数据是否已写入本地文件的标识
    private var hasCapture = true
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(mBinding.root)
        mBinding.rowImage.setOnClickListener {
            hasRowWrite = false
        }
        mBinding.rotateImage.setOnClickListener {
            hasRowRotateWrite = false
        }
        mBinding.capture?.setOnClickListener {
            hasCapture = false
        }
        checkAndRequestPermission(Manifest.permission.CAMERA, Runnable {
            startScan()
        }, Runnable {
            showToast("未授予相机权限")
        })
    }
// TODO: CameraX 使用 YUV420_888 来生成图像，
//  该格式有 8 位的 Luma(Y)、Chroma(U, V) 和 Paddings(P) 三个通道
    /**
     * 用户可以授权成功后调用此开始进行扫码
     */
    open fun startScan() {
        if (!checkPermission()) {
            return
        }
        if (mCameraProviderFuture == null) {
            mCameraProviderFuture = ProcessCameraProvider.getInstance(this)
            mCameraProviderFuture!!.addListener(Runnable {
                val cameraProvider = mCameraProviderFuture!!.get()
                bindPreview(cameraProvider)
            }, ContextCompat.getMainExecutor(this))
        }
    }

    /**
     * 检查相机权限
     */
    private fun checkPermission(): Boolean {
        return ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED
    }

    private fun bindPreview(cameraProvider: ProcessCameraProvider) {
        val imageAnalysis = ImageAnalysis.Builder()
//            .setTargetResolution(Size(1280, 720))
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .build()

        imageAnalysis.setAnalyzer(
            Executors.newSingleThreadExecutor(),
            ImageAnalysis.Analyzer { imageProxy ->
                try {
                    Log.i("123456", "cropRect=${imageProxy.cropRect}")

                    handleRow(imageProxy)
                    handleRowRotate(imageProxy)
                    handleYPlaneRow(imageProxy)
                    handleYPlaneRotate(imageProxy)

                } finally {
                    imageProxy.close()
                }
            }
        )
        var preview: Preview = Preview.Builder()
            .build()

        var cameraSelector: CameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build()

        preview.setSurfaceProvider(mBinding.previewView.surfaceProvider)

        mCamera = cameraProvider.bindToLifecycle(
            this,
            cameraSelector,
            imageAnalysis,
            preview
        )
    }

    private fun handleRowRotate(imageProxy: ImageProxy) {
        var width = imageProxy.width
        var height = imageProxy.height
        val byteArray: ByteArray
        val rotateDatas: ByteArray
        when (mBinding.radioGroup?.checkedRadioButtonId) {

            R.id.nv12 -> {
                rotateDatas = RotationUtil.nv12ToI420Rotate(
                    imageProxy.getNV12Datas(),
                    width,
                    height,
                    imageProxy.imageInfo.rotationDegrees
                ) ?: return
                if (imageProxy.imageInfo.rotationDegrees == 90 || imageProxy.imageInfo.rotationDegrees == 270) {
                    width = imageProxy.height
                    height = imageProxy.width
                }
                byteArray = ConvertUtil.i420ToRGB24(rotateDatas, width, height)!!
            }
            else -> {
                rotateDatas = RotationUtil.i420Rotate(
                    imageProxy.getI420Datas(),
                    width,
                    height,
                    imageProxy.imageInfo.rotationDegrees
                ) ?: return
                if (imageProxy.imageInfo.rotationDegrees == 90 || imageProxy.imageInfo.rotationDegrees == 270) {
                    width = imageProxy.height
                    height = imageProxy.width
                }
                byteArray = ConvertUtil.i420ToRGB24(rotateDatas, width, height)!!

            }
        }

        if (!hasRowRotateWrite) {
            val file = File(
                externalCacheDir,
                "i420_${width}x${height}_${Calendar.getInstance().timeInMillis}.yuv"
            )
            FileOutputStream(file).use {
                it.write(rotateDatas)
                showToast("yuv数据已写入本地：${file.absolutePath}")
            }
            hasRowRotateWrite = true
        }

        val colors = YUVUtil.rgb24ToColors(byteArray, width, height)
        val bmp = Bitmap.createBitmap(
            colors!!, 0, width, width, height,
            Bitmap.Config.RGB_565
        )
        runOnUiThread {
            mBinding.rotateImage.setImageBitmap(bmp)
        }

        if (!hasCapture) {
            val intent = Intent(this, DemoActivity::class.java)
            MyApp.INSTANCE.i420Data = I420Data(rotateDatas, width, height)
            startActivity(intent)
            hasCapture = true
        }
    }


    private fun handleRow(imageProxy: ImageProxy) {
        val width = imageProxy.width
        val height = imageProxy.height
        var byteArray: ByteArray
        when (mBinding.radioGroup?.checkedRadioButtonId) {

            R.id.nv12 -> {
                val datas = imageProxy.getNV12Datas()
                if (!hasRowWrite) {
                    val file = File(
                        externalCacheDir,
                        "nv12_${width}x${height}_${Calendar.getInstance().timeInMillis}.yuv"
                    )
                    FileOutputStream(file).use {
                        it.write(datas)
                        showToast("yuv数据已写入本地：${file.absolutePath}")
                    }
                    hasRowWrite = true
                }
                byteArray = ConvertUtil.nv12ToRGB24(datas, width, height)!!
            }
            R.id.nv21 -> {
                val datas = imageProxy.getNV21Datas()
                if (!hasRowWrite) {
                    val file = File(
                        externalCacheDir,
                        "nv21_${width}x${height}_${Calendar.getInstance().timeInMillis}.yuv"
                    )
                    FileOutputStream(file).use {
                        it.write(datas)
                        showToast("yuv数据已写入本地：${file.absolutePath}")
                    }
                    hasRowWrite = true
                }
                byteArray = ConvertUtil.nv21ToRGB24(datas, width, height)!!
            }
            else -> {
                val datas = imageProxy.getI420Datas()
                if (!hasRowWrite) {
                    val file = File(
                        externalCacheDir,
                        "i420_${width}x${height}_${Calendar.getInstance().timeInMillis}.yuv"
                    )
                    FileOutputStream(file).use {
                        it.write(datas)
                        showToast("yuv数据已写入本地：${file.absolutePath}")
                    }
                    hasRowWrite = true
                }
                byteArray = ConvertUtil.i420ToRGB24(datas, width, height)!!
            }
        }


        val colors = YUVUtil.rgb24ToColors(byteArray, width, height)
        val bmp = Bitmap.createBitmap(
            colors!!, 0, width, width, height,
            Bitmap.Config.RGB_565
        )
        runOnUiThread {
            mBinding.rowImage.setImageBitmap(bmp)
        }
    }

    private fun handleYPlaneRow(imageProxy: ImageProxy) {
        val yDatas = imageProxy.getYPlaneDatas()
        val colors = YUVUtil.yPlaneToColors(yDatas, imageProxy.width, imageProxy.height)
        val bmp = Bitmap.createBitmap(
            colors!!, 0, imageProxy.width, imageProxy.width, imageProxy.height,
            Bitmap.Config.RGB_565
        )
        runOnUiThread {
            mBinding.grayImage.setImageBitmap(bmp)
        }
    }

    private fun handleYPlaneRotate(imageProxy: ImageProxy) {
        var rotationDegrees=imageProxy.imageInfo.rotationDegrees
        val yDatas = imageProxy.getYPlaneDatas()
        val rotateDatas = RotationUtil.rotateYPlane(
            yDatas,
            imageProxy.width,
            imageProxy.height,
            rotationDegrees
        ) ?: return

        //测试用
//        val rotateDatas=YUVUtil.rotateYPlane( yDatas,
//            imageProxy.width,
//            imageProxy.height,
//            rotationDegrees) ?: return
        var stride = imageProxy.width
        var width = imageProxy.width
        var height = imageProxy.height
        if (rotationDegrees == 90 ||
            rotationDegrees == 270
        ) {
            stride = imageProxy.height
            width = imageProxy.height
            height = imageProxy.width
        }
        val colors = YUVUtil.yPlaneToColors(rotateDatas, width, height)
        val bmp = Bitmap.createBitmap(
            colors!!, 0, stride, width, height,
            Bitmap.Config.RGB_565
        )
        runOnUiThread {
            mBinding.grayFollowImage.setImageBitmap(bmp)
        }
    }


}